﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Postnuclear.Test.Helpers
  {
  /// <summary>
  /// Tests <see cref="ICollection{T}"/> implementation behavior.
  /// </summary>
  public static class CollectionValidator
    {
    #region Public

    // Methods

    /// <summary>
    /// Validates the specified collection.
    /// </summary>
    /// <typeparam name="T">Type of collection items.</typeparam>
    /// <param name="collectionCreator">The collection creator.</param>
    /// <param name="itemCreator">The item creator.</param>
    public static void Validate<T>(Func<ICollection<T>> collectionCreator, Func<T> itemCreator)
      {
      ModifyCollectionTest(collectionCreator, itemCreator);
      }

    #endregion

    #region Private

    // Methods

    private static void ModifyCollectionTest<T>(Func<ICollection<T>> collectionCreator, Func<T> itemCreator)
      {
      ICollection<T> collection = collectionCreator();
      T first = itemCreator();
      T second = itemCreator();

      AddTest(collection, first, second);
      RemoveTest(collection, first, second);
      ClearTest(collection, first, second);
      }

    private static void AddTest<T>(ICollection<T> collection, T first, T second)
      {
      Assert.AreEqual(0, collection.Count);
      Assert.IsFalse(collection.Contains(first));
      Assert.IsFalse(collection.Contains(second));

      collection.Add(first);
      Assert.AreEqual(1, collection.Count);
      Assert.IsTrue(collection.Contains(first));
      Assert.IsFalse(collection.Contains(second));

      collection.Add(second);
      Assert.AreEqual(2, collection.Count);
      Assert.IsTrue(collection.Contains(first));
      Assert.IsTrue(collection.Contains(second));
      }

    private static void RemoveTest<T>(ICollection<T> collection, T first, T second)
      {
      Assert.AreEqual(2, collection.Count);
      Assert.IsTrue(collection.Contains(first));
      Assert.IsTrue(collection.Contains(second));

      Assert.IsTrue(collection.Remove(first));
      Assert.AreEqual(1, collection.Count);
      Assert.IsFalse(collection.Contains(first));
      Assert.IsTrue(collection.Contains(second));

      Assert.IsFalse(collection.Remove(first));
      Assert.AreEqual(1, collection.Count);
      Assert.IsFalse(collection.Contains(first));
      Assert.IsTrue(collection.Contains(second));
      }

    private static void ClearTest<T>(ICollection<T> collection, T first, T second)
      {
      Assert.AreEqual(1, collection.Count);
      Assert.IsFalse(collection.Contains(first));
      Assert.IsTrue(collection.Contains(second));

      collection.Clear();
      Assert.AreEqual(0, collection.Count);
      Assert.IsFalse(collection.Contains(first));
      Assert.IsFalse(collection.Contains(second));
      }

    #endregion
    }
  }
